package com.luo.d3s.ec.application.service.impl;

import com.luo.d3s.core.application.dto.Response;
import com.luo.d3s.core.application.dto.SingleResponse;
import com.luo.d3s.core.util.Optionals;
import com.luo.d3s.core.util.validation.Validates;
import com.luo.d3s.ec.application.assembler.CategoryAssembler;
import com.luo.d3s.ec.application.dto.vo.CategoryVo;
import com.luo.d3s.ec.application.dto.command.CategoryCreateCommand;
import com.luo.d3s.ec.application.dto.command.CategoryModifyCommand;
import com.luo.d3s.ec.application.service.CategoryCommandService;
import com.luo.d3s.ec.application.service.CategoryQueryService;
import com.luo.d3s.ec.domain.category.model.Category;
import com.luo.d3s.ec.domain.category.model.CategoryDesc;
import com.luo.d3s.ec.domain.category.model.CategoryFactory;
import com.luo.d3s.ec.domain.category.model.CategoryName;
import com.luo.d3s.ec.domain.category.repository.CategoryRepository;
import com.luo.d3s.ec.domain.service.CategorySubIdsService;
import com.luo.d3s.ec.domain.specification.CategorySpecification;
import com.luo.d3s.ec.domain.specification.GoodsNotExistInCategoriesSpecification;
import com.luo.d3s.share.model.BizId;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 分类命令处理服务实现类
 *
 * @author luohq
 * @date 2023-01-04 17:06
 */
@Service
@CacheConfig(cacheNames = CategoryQueryService.CATEGORY_TREE_CACHE_NAME)
@CacheEvict(allEntries = true)
public class CategoryCommandServiceImpl implements CategoryCommandService {

    private CategoryRepository categoryRepository;
    private CategorySubIdsService categorySubIdsService;
    private CategorySpecification categorySpecification;
    private  GoodsNotExistInCategoriesSpecification goodsNotExistInCategoriesSpecification;


    public CategoryCommandServiceImpl(CategoryRepository categoryRepository,
                                      CategorySubIdsService categorySubIdsService, CategorySpecification categorySpecification,
                                      GoodsNotExistInCategoriesSpecification goodsNotExistInCategoriesSpecification) {
        this.categoryRepository = categoryRepository;
        this.categorySubIdsService = categorySubIdsService;
        this.categorySpecification = categorySpecification;
        this.goodsNotExistInCategoriesSpecification = goodsNotExistInCategoriesSpecification;
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public SingleResponse<CategoryVo> createCategory(CategoryCreateCommand categoryCreateCommand) {
        //创建分类实体
        Category category = CategoryFactory.createCategory(
                Optionals.defaultNull(categoryCreateCommand.getParentCategoryId(), BizId::of),
                CategoryName.of(categoryCreateCommand.getCategoryName()),
                Optionals.defaultNull(categoryCreateCommand.getCategoryDesc(), CategoryDesc::of)
        );
        //验证新增分类是否合法
        //方式1：每次都new领域服务
        //CategorySpecification categorySpecification = new CategorySpecification(this.categoryRepository);
        //categorySpecification.isSatisfiedBy(category);
        //方式2：通过领域对象注册中心获取
        //DomainRegistry.specification(CategorySpecification.class).isSatisfiedBy(category);
        //方式3【推荐】：通过@D3sComponentScan自动注册领域服务为Spring Bean
        this.categorySpecification.isSatisfiedBy(category);
        //保存分类
        category = this.categoryRepository.save(category);
        //转换CategoryDto
        return SingleResponse.of(CategoryAssembler.toCategoryVo(category));
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Response modifyCategory(CategoryModifyCommand categoryModifyCommand) {
        //查询分类实体
        Category category = this.categoryRepository.findById(BizId.of(categoryModifyCommand.getId()));
        Validates.notNull(category, "category does not exist");
        //修改基础信息
        category.modifyBasicInfo(Optionals.defaultNull(categoryModifyCommand.getParentCategoryId(), BizId::of),
                CategoryName.of(categoryModifyCommand.getCategoryName()), CategoryDesc.of(categoryModifyCommand.getCategoryDesc()));
        //验证待修改分类是否合法
        this.categorySpecification.isSatisfiedBy(category);
        //保存实体
        this.categoryRepository.save(category);
        return Response.buildSuccess();
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Response removeCategory(Long categoryId) {
        //转换分类ID
        BizId categoryEntityId = BizId.of(categoryId);
        //调用领域服务查询当前分类的所有子分类ID
        List<BizId> subCategoryIdsWithParentId = this.categorySubIdsService.extractSubCategoryIds(categoryEntityId);
        //验证待删除的分类ID下不存在商品
        this.goodsNotExistInCategoriesSpecification.isSatisfiedBy(subCategoryIdsWithParentId);
        //批量删除当前分类及其子分类
        this.categoryRepository.deleteByIds(subCategoryIdsWithParentId);
        return Response.buildSuccess();
    }
}
